package com.lt.app;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.text.TextUtils;

import com.lt.common.DebugHelper;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.cert.Certificate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 获取apk或者app的签名信息
 */
public class SignHelper {

    private static SignHelper instance;

    private SignHelper() {
    }

    public static SignHelper getInstance() {
        if (instance == null) {
            synchronized (SignHelper.class) {
                instance = new SignHelper();
            }
        }
        return instance;
    }

    /**
     * 从 apk 中获取 MD5 签名信息
     *
     * @param apkPath apk路径
     * @throws Exception
     */
    public String getApkSignatureMD5(String apkPath) throws Exception {
        byte[] bytes = getSignaturesFromApk(apkPath);
        return hexDigest(bytes, "MD5");
    }

    public String getApkSignatureSHA1(String apkPath) throws Exception {
        byte[] bytes = getSignaturesFromApk(apkPath);
        return hexDigest(bytes, "SHA1");
    }

    public String getApkSignatureSHA256(String apkPath) throws Exception {
        byte[] bytes = getSignaturesFromApk(apkPath);
        return hexDigest(bytes, "SHA256");
    }

    /**
     * 获取已经安装的 app 的 MD5 签名信息
     */
    public String getAppSignatureMD5(Context context, String pkgName) {
        return getAppSignature(context, pkgName, "MD5");
    }

    public String getAppSignatureSHA1(Context context, String pkgName) {
        return getAppSignature(context, pkgName, "SHA1");
    }

    public String getAppSignatureSHA256(Context context, String pkgName) {
        return getAppSignature(context, pkgName, "SHA256");
    }

    public String getAppSignature(Context context, String pkgName, String algorithm) {
        try {
            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
                    pkgName, PackageManager.GET_SIGNATURES);
            Signature[] signs = packageInfo.signatures;
            Signature sign = signs[0];
            return hexDigest(sign.toByteArray(), algorithm);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 从APK中读取签名
     *
     * @throws IOException
     */
    public byte[] getSignaturesFromApk(String apkPath) throws IOException {
        File file = new File(apkPath);
        JarFile jarFile = new JarFile(file);
        try {
            JarEntry je = jarFile.getJarEntry("AndroidManifest.xml");
            byte[] readBuffer = new byte[8192];
            Certificate[] certs = loadCertificates(jarFile, je, readBuffer);
            if (certs != null) {
                for (Certificate c : certs) {
                    return c.getEncoded();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 加载签名
     */
    public Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer) {
        try {
            InputStream is = jarFile.getInputStream(je);
            while (is.read(readBuffer, 0, readBuffer.length) != -1) {
            }
            is.close();
            return je != null ? je.getCertificates() : null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String hexDigest(byte[] bytes, String algorithm) {
        MessageDigest md5;
        try {
            md5 = MessageDigest.getInstance(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        byte[] md5Bytes = md5.digest(bytes);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

    public String getFriendlySign(String sign) {
        StringBuilder sb = new StringBuilder();
        if (!TextUtils.isEmpty(sign)) {
            if (sign.length() < 2) {
                return sign.toUpperCase();
            } else {
                int size = (int) Math.ceil(((double) sign.length()) / 2);
                for (int i = 0; i < size; i++) {
                    if (i == 0) {
                        sb.append(sign.substring(0, 2).toUpperCase());
                    } else if (i == size - 1) {
                        sb.append(":");
                        sb.append(sign.substring(i * 2).toUpperCase());
                    } else {
                        sb.append(":");
                        sb.append(sign.substring(i * 2, i * 2 + 2).toUpperCase());
                    }
                }
            }
        }
        return sb.toString();
    }


    public void printAll(Context ctx, String pkgName) {
        String md5 = getAppSignatureMD5(ctx, pkgName);
        DebugHelper.e("md5:" + md5);
        DebugHelper.e("md5:" + getFriendlySign(md5));
        String sha1 = getAppSignatureSHA1(ctx, pkgName);
        DebugHelper.e("sha1:" + sha1);
        DebugHelper.e("sha1:" + getFriendlySign(sha1));
        String sha256 = getAppSignatureSHA256(ctx, pkgName);
        DebugHelper.e("sha256:" + sha256);
        DebugHelper.e("sha256:" + getFriendlySign(sha256));
    }
}
